### -*- coding: utf-8 -*- #############################################
# Разработано Паэглит Арвидом (http://arvid.dp.ua/)
# Все права защищены, 2007
#
# Developed by Paeglit Arvid (http://arvid.dp.ua/)
# All right reserved, 2007
#######################################################################
"""TeoreticalMixture class for the Zope 3 based diplom package

$Id: mixture.py 67 2007-12-29 02:41:01Z Arvi3D $
"""
__author__  = "Arvid"
__license__ = "GPL"
__version__ = "$Revision: 67 $"
__date__ = "$Date: 2007-12-29 02:41:01 +0000 (Sat, 29 Dec 2007) $"

from zope.app import zapi
from zope.schema.fieldproperty import FieldProperty
from zope.interface import implements,implementedBy
from zope.cachedescriptors.property import CachedProperty
from persistent import Persistent
from zope.app.container.contained import Contained

from random import random
from math import sqrt, exp

from interfaces import ITeoreticalMixture, ITeoreticalDistributing

class TeoreticalMixture(Persistent, Contained) :
    implements(ITeoreticalMixture)

    #XXX: обязательно убрать этот беспредел
    distributings = ('expo', 'expo') #FieldProperty(ITeoreticalMixture['distributings'])

    @property
    def first(self):
        return len(self.distributings) >=1 \
                and zapi.getUtility(ITeoreticalDistributing, context = self, name = self.distributings[0]) \
                or None

    @property
    def second(self):
        return len(self.distributings) >=2 \
                and zapi.getUtility(ITeoreticalDistributing, context = self, name = self.distributings[1]) \
                or None

    def distributing(self, x, weight, *params):
        """ distributing function """
        first = self.first
        second = self.second
        return weight*first.distributing(x, *params[:first.paramCount]) \
                + (1-weight)*second.distributing(x, *params[first.paramCount:])

    def closeness(self, x, *params):
        """ closeness function """
        first = self.first
        second = self.second
        return weight*first.closeness(x, *params[:first.paramCount]) \
                + (1-weight)*second.closeness(x, *params[first.paramCount:])

    def generate(self, weight, *params):
        """ generate one elements of this common distributing """
        if random() <= weight:
            return self.first.generate(*params[:first.paramCount])
        else:
            return self.second.generate(*params[first.paramCount:])

    def eksces(self, weight):
        return weight*self.first.eksces + (1.0-weight)*self.second.eksces

    @property
    def paramCount(self):
        return 1 + self.first.paramCount + self.second.paramCount

